# /user/bin/python3
# -*- coding: utf-8 -*-
# @Time       : 2019/10/24 20:55
# @Author     : CHD
# @File       : evolution.py
# @Software   : Sumblime Text3

import numpy as np
import random
import matplotlib.pyplot as plt
from matplotlib import font_manager
my_font = font_manager.FontProperties(fname = "C:/Windows/Fonts/msyh.ttc")

# 定义解码和编码类
class Decode_encode():
	def __init__(self, var_range, precision):
		import math
		self.var_range = var_range
		self.precision = precision
		self.m = [0 for j in range(len(var_range))]
		for i in range(len(self.var_range)):
			self.m[i] = math.floor(math.log((self.var_range[i][1] - self.var_range[i][0]) * self.precision, 2)) + 1

	# 定义编码函数
	def encode(self, x):
		x_encode = []
		for i in range(len(self.var_range)):
			y = (x[i]- self.var_range[i][0]) * ((2**self.m[i]) / (self.var_range[i][1] -self.var_range[i][0]))    
			for j in range(self.m[i], 0, -1):
				if (y - 2**(j-1)) >= 0:
					y = y - 2**(j-1)
					x_encode.append(1)   
				else:
					x_encode.append(0)
		return x_encode

	# 定义解码函数
	def decode(self, vector):
		import copy 
		vector_ = copy.deepcopy(vector) 
		d = [0 for k in range(len(self.m))]
		x = [0 for k in range(len(self.m))]
		vectors = [[] for i in range(len(self.m))] 
		for i in range(len(self.m)):
			for j in range(self.m[i]):
				vectors[i].append(vector_.pop(0))
				d[i] += 2**(self.m[i]-1-j)*vectors[i][j]	
			x[i] = self.var_range[i][0] + d[i]*((self.var_range[i][1] - self.var_range[i][0]) / (2**self.m[i]-1))
			x[i] = round(x[i], 6)
		return x

# 定义评估函数
def eval(x):
	'''x取值根据需要取值x1,x2,x3……'''
	import math
	return 21.5 + x[0]*math.sin(4*math.pi*x[0]) + x[1]*math.sin(20*math.pi*x[1])

# 定义进化算法
def evolution(v_inits, iterations, obj):
	'''输入参数为随机初始化种子，迭代次数以及编码和解码的对象'''
	# 初始化
	v = v_inits # 编码值
	v_ = [0 for j in range(len(v_init))] # 解码值
	evals =  [0 for j in range(len(v_init))] # 各种子的评估函数值
	p = [0 for j in range(len(v_init))] # 各种子评估函数占总体的比例
	q = [0 for j in range(len(v_init))] # 圆盘
	v_youshi = [0 for j in range(len(v_init))] # 具有优势的种子
	max_evals = 0 #最大的评估函数值
	point_x = []
	point_y = []
	point_z = []

	# 将种子解码，并计算评估函数值
	for iters in range(iterations):
		for i in range(len(v)):
			v_ [i] = obj.decode(v[i])
			evals[i] = (eval(v_[i]))
			if evals[i] > max_evals:
				max_evals = evals[i]
				v_max = v_[i]
				iteration = iters

		# 求种子的适应度
		p = [(evals[j] / sum(evals)) for j in range(len(v))]
		q = [sum(p[0:j+1]) for j in range(len(v))]

		# 计算优势种群
		for  j in range(10):
			random_number = random.random()
			for i in range(10):
				if i == 0 and 0 < random_number < q[0]:
					v_youshi[j] = v[i]
				else:
					if q[i] >= random_number > q[i-1]:
						v_youshi[j] = v[i]

		# 单点交叉
		for i in range(0,10,2):
			cut_number = random.randint(0, 32)
			temp = v[i][cut_number:]
			v[i][cut_number:] = v[i+1][cut_number:]
			v[i+1][cut_number:] = temp
		
		# 变异
		for i in range(10):
			cut_number = random.randint(0, 32)
			v[i][cut_number] = (v[i][cut_number] + 1) % 2
		
		point_x.append(iters)
		point_y.append(max_evals)
		point_z.append(max(evals))
	
	# 绘制图像
	plt.ylim(0,55)
	plt.xlim(0, 1050)
	plt.xlabel(u'迭代次数', fontproperties=my_font)
	plt.ylabel(u'函数值', fontproperties=my_font)
	plt.title(u"进化算法在不同迭代次数下的函数值", fontproperties=my_font)
	describle = 'Iteration:' + str(iteration) + '\n' + 'max_value:' + str(max_evals) + '\n' + '[x1, x2] = ' + str(v_max)
	plt.annotate(describle, xy=(iteration, max_evals), xytext=(iteration, 45), fontsize=9, arrowprops=dict(facecolor='purple',shrink=0.002))
	plt.plot(point_x, point_y, c='b')
	plt.plot(point_x, point_z, c='r')
	plt.show()
	return iteration, max_evals, v_max	

if __name__ == '__main__':
	# 输入数据：变量范围和精度
	var_range = [(-3.0, 12.1), (4.1, 5.8)]
	precision = 10**4
	obj = Decode_encode(var_range, precision)
	# 迭代次数为1000次
	iterations = 1000
	# 随机初始化10个种子
	v_init = [0 for i in range(10)] # 编码值
	for i in range(10):
		v_init[i] = [random.randint(0,1) for i in range(sum(obj.m))]
	print(evolution(v_init, iterations, obj))
